
#include "GDLink.h"
#include "Macro_DLink.h"
#include "cc_pub.h"	

/*** interior	define ***********/

#define LLOG
#define LLOG_ERR
#define LLOG_MARK
#include "llog.h"

// #ifdef CFG_SYS_MALLOC
// #define L_MALLOC(A) 	MALLOC(A)
// #define L_FREE(A)	MFREE(A)
// #endif

#ifdef	CFG_STATIC_BUF_ALLOCATE
#define L_MALLOC 	SMalloc
#define L_FREE(A) 	LLOG_ERR()
#else
#define L_MALLOC 	malloc
#define L_FREE(A)	free(A)
#endif

/*** interior  struct **********/

/*** global val ***************/

/*** local function **************/

/*** TODO ************************/

//
#ifdef CFG_GDLINK_MODE	/*** 创建链表管理对象 */
static int GDLink_Init(tGDLHead* pObj,tpCmpRule pObjCmp){
	
	int ret=RET_ERR;
	
	MEMSET((uint8_t*)pObj,0,sizeof(tGDLHead));
	pObj->pObjCmp=pObjCmp;
	return ret;
}

tGDLHead* GDLink_CreateByName(const uint8_t* pName,tpCmpRule pObjCmp){
	
	tGDLHead* pObj=NULL;
	pObj=(tGDLHead*)L_MALLOC(sizeof(tGDLHead));
	if(pObj == NULL){
		return pObj;
	}

	MEMSET((uint8_t*)pObj,0,sizeof(tGDLHead));
	pObj->pObjCmp	= pObjCmp;
	pObj->pName		= pName;
	
	return pObj;
}

int GDLink_SetCmp(tGDLHead* pObj,tpCmpRule pCmp){
	pObj->pObjCmp = pCmp;
	return RET_OK;
}

static tDLNode* GDLink_GetEndNode(tGDLHead* pObj){ 
    
    tDLNode* ptmp=NULL;
	
	if(pObj == NULL) 		return ptmp;
	if(pObj->pHead == NULL) return ptmp;
		
	ptmp = pObj->pHead->pPrev;
    return ptmp;
}

/* 基本 Node 的 Search+遍历Traverse */ 
int GDLink_ShowCBF(uint8_t* pStr,tGDLHead* pObj,int (*pFunc)(tDLNode* pNode)){
	//
	int index=0;
    tDLNode* ptmp=NULL;
	
	if(pObj == NULL) 			return index;

	if(pStr != NULL){
		LLOG("#I %s ",pStr);
	}
	
	if(pObj->pHead == NULL){
		LLOG("#I DLink is Empty\n");
		return index;
	}	
	LLOG("Cnt[%d]: ",pObj->NumCnt);
	//
	index=0;
	ptmp=pObj->pHead;
    while(1){
		if(pFunc != NULL){
			if(RET_ERR == pFunc(ptmp)){
				break;
			}
		}
		else{
			LLOG("->%d[%x]",index++,ptmp); // 不太具有可读性
		}
		
		GDLINK_ITERATOR_DOWN(pObj->pHead,ptmp);
    }
	LLOG("\n");
    return index;   
}

/* int GDLink_Show(uint8_t* pStr,tGDLHead* pObj){
	return GDLink_ShowCBF(pStr,pObj,NULL);  
} */

static tDLNode* GDLink_Check_IsDLinkNode(tGDLHead* pObj,tDLNode* pCheckNode){ 
	//
    tDLNode* ptmp = NULL;
	
	if(pObj == NULL) 			{ LLOG_ERR(); return ptmp;}
	if(pObj->pHead == NULL) 	{ LLOG_ERR(); return ptmp;}
	if(pCheckNode == NULL) 		{ LLOG_ERR(); return ptmp;}

    ptmp=pObj->pHead;
    while(1){
		// TODO:
        if( pCheckNode == ptmp){ // ok
            break;
        } 

		GDLINK_ITERATOR_DOWN(pObj->pHead,ptmp); // GDLINK_ITERATOR_LOOP
	}
    return ptmp;    
}

static tDLNode* GDLink_RingSearchUp(tGDLHead* pObj,tDLNode* pStartNode,void* pInPara){ // 暂不对外释放

    tDLNode* ptmp=NULL;
	
	if(pObj == NULL) 			{ LLOG_ERR(); return ptmp;}
	if(pInPara == NULL) 		{ LLOG_ERR(); return ptmp;}
	if(pObj->pObjCmp == NULL) 	{ LLOG_ERR(); return ptmp;}
	if(pStartNode == NULL) 		{ LLOG_ERR(); return ptmp;}
	
    ptmp=pStartNode;
    while(1){
        if( RET_EQ == pObj->pObjCmp(pInPara,(void*)ptmp)){
            break;
        } 
		
		GDLINK_ITERATOR_UP(pStartNode,ptmp);
    }
    return ptmp;    
}

static tDLNode* GDLink_RingSearchDown(tGDLHead* pObj,tDLNode* pStartNode,void* pInPara){

    tDLNode* ptmp=NULL;
	
	if(pObj == NULL) 			{ LLOG_ERR(); return ptmp;}
	if(pInPara == NULL) 		{ LLOG_ERR(); return ptmp;}
	if(pObj->pObjCmp == NULL) 	{ LLOG_ERR(); return ptmp;}	
	if(pStartNode == NULL) 		{ LLOG_ERR(); return ptmp;}	
    
    ptmp = pStartNode;
    while(1){
        if( RET_EQ == pObj->pObjCmp(pInPara,(void*)ptmp)){
            break;
        }
		
		GDLINK_ITERATOR_DOWN(pStartNode,ptmp);
    }
    return ptmp;    
}

#endif

#ifdef CFG_GDLINK_MODE	/*** 通用 的 插入，删除 操作 */	

tDLNode* GDLink_Search(tGDLHead* pObj,void* pInPara){
	//
	if(pObj == NULL) 			{ LLOG_ERR(); return NULL;}
	return GDLink_RingSearchDown(pObj,pObj->pHead,pInPara); 
}

int GDLink_Notify(tGDLHead* pObj,int (*pFunc)(tDLNode* pNode)){
	// 
	int ret=RET_ERR;
    tDLNode* ptmp=NULL;

	if(pObj == NULL) 			{ LLOG_ERR(); return ret;}
	if(pFunc == NULL)			{ LLOG_ERR(); return ret;}	
	if(pObj->pHead == NULL)		{ LLOG_ERR(); return ret;}	

	ret=RET_OK;

	ptmp=pObj->pHead;
    while(1){
		if(RET_ERR == pFunc(ptmp)){
			break;
		}
		
		GDLINK_ITERATOR_DOWN(pObj->pHead,ptmp);
    }
    return ret;    
}

#define GDLINK_ADD_CNT()  pObj->NumCnt++
#define GDLINK_SUB_CNT()  if(pObj->NumCnt > 0) pObj->NumCnt--
// T- pNowNode 检查是否必须？接口安全与效率的选择？
int GDLink_AddAfter(tGDLHead* pObj,tDLNode* pNowNode,tDLNode* pAddNode){   
    int ret=RET_ERR;

	tDLNode* ptmp;
	
	if(pObj == NULL) 		{ LLOG_ERR(); return ret;}
	if(pAddNode	== NULL) 	{ LLOG_ERR(); return ret;}

	if((pObj->pHead == NULL) && (pNowNode==NULL)){	// Frist Node
		GDLNODE_INSERT_LOOPHEAD(pObj->pHead,pAddNode);
		GDLINK_ADD_CNT();
		return RET_OK;
	}
	
	ptmp=GDLink_Check_IsDLinkNode(pObj,pNowNode);
	if(ptmp == NULL){
		return ret;
	}
    ret=RET_OK;

	GDLNODE_INSERT_AFTER(pNowNode,pAddNode); // Mark
    GDLINK_ADD_CNT();
	
    return ret;   
}

int GDLink_AddBefore(tGDLHead* pObj,tDLNode* pNowNode,tDLNode* pAddNode){   
    int ret=RET_ERR;
	tDLNode* ptmp;
	
	if(pObj == NULL) 		{ LLOG_ERR(); return ret;}
	if(pAddNode	== NULL) 	{ LLOG_ERR(); return ret;}	
	
	if((pObj->pHead == NULL) && (pNowNode==NULL)){ // Frist Node
		GDLNODE_INSERT_LOOPHEAD(pObj->pHead,pAddNode);
		GDLINK_ADD_CNT();
		return RET_OK;
	}		
	
	ptmp=GDLink_Check_IsDLinkNode(pObj,pNowNode);
	if(ptmp == NULL){
		return ret;
	}
    ret=RET_OK;

	//todo
	GDLNODE_INSERT_BEFORE(pObj->pHead,ptmp,pAddNode);
    GDLINK_ADD_CNT();
    return ret;   
}
//
int GDLink_AddToHead(tGDLHead* pObj,tDLNode* pAddNode){   

    int ret=RET_ERR;
    tDLNode* ptmp;
	
	if(pObj == NULL) 		{ LLOG_ERR(); return ret;}
	if(pAddNode	== NULL) 	{ LLOG_ERR(); return ret;}
	
	ret=RET_OK;
    if(pObj->pHead == NULL){ 
		GDLNODE_INSERT_LOOPHEAD(pObj->pHead,pAddNode);
		GDLINK_ADD_CNT();
		return ret;
	}   
    
	ptmp=pObj->pHead;
	GDLNODE_INSERT_BEFORE(pObj->pHead,ptmp,pAddNode);
	GDLINK_ADD_CNT();
	
    return ret;
}

int GDLink_AddToTail(tGDLHead* pObj,tDLNode* pAddNode){
	// 
    tDLNode* ptmp;
	int ret=RET_ERR;
	if(pObj == NULL) 		{ LLOG_ERR(); return ret;}
	if(pAddNode	== NULL) 	{ LLOG_ERR(); return ret;}
	
	ret = RET_OK;
    if(pObj->pHead == NULL){ 
		GDLNODE_INSERT_LOOPHEAD(pObj->pHead,pAddNode);
		GDLINK_ADD_CNT();
		return ret;
	}  

	ptmp=GDLink_GetEndNode(pObj);
	if(ptmp	== NULL) 	{ LLOG_ERR(); return RET_ERR;}
		
	GDLNODE_INSERT_AFTER(ptmp,pAddNode);   
	GDLINK_ADD_CNT();
	
    return ret;
}

tDLNode* GDLink_DelByNodePtr(tGDLHead* pObj,tDLNode* pDelNode){
    // rule: 返回删除节点指针 ； 输入 node 指针
    tDLNode* ptmp=NULL;
	
	if(pObj == NULL) 			return ptmp;
	if(pObj->pHead == NULL) 	return ptmp;

	ptmp=GDLink_Check_IsDLinkNode(pObj,pDelNode);
	if(ptmp == NULL){  //
		return ptmp; 
	}
	GDLNODE_REMOVE(pObj->pHead,ptmp);
	GDLINK_SUB_CNT();
    return ptmp;     
}

int GDLink_CleanALL(tGDLHead* pObj){                                //
    
	int ret=RET_ERR;
    tDLNode* ptmp=NULL;
	
	if(pObj == NULL) 			return ret;
	if(pObj->pHead == NULL) 	return ret;
	
	ptmp=pObj->pHead;
    while(1){
        if(pObj->pHead == NULL){
			ret=RET_OK;
            break;
        }
		
		
        // TODO :
		GDLNODE_REMOVE(pObj->pHead,ptmp);
		GDLINK_SUB_CNT();
		ptmp = pObj->pHead;
		// TODO :
    }
	return ret;    
}

int GDLink_SortAdd(tGDLHead* pObj,tDLNode* pAddNode){

	int ret=RET_ERR;
	int cmpret;
    tDLNode* ptmp=NULL;
	uint8_t UpDown;
	
	if(pObj == NULL) 			return ret;
	if(pAddNode == NULL)		return ret;	

	if((pObj->pHead == NULL)){	// Frist Node
		GDLNODE_INSERT_LOOPHEAD(pObj->pHead,pAddNode);
		GDLINK_ADD_CNT();
		LLOG_MARK();
		return RET_OK;
	}

	ptmp=pObj->pHead;
    while(1){

		if(RET_GT == pObj->pObjCmp((void*)pAddNode,(void*)ptmp) ){ 
			// LLOG_MARK();
		}
		else{
			//todo
			ret=RET_OK;
			GDLNODE_INSERT_BEFORE(pObj->pHead,ptmp,pAddNode);
			GDLINK_ADD_CNT();
			break;
		}
		
		GDLINK_ITERATOR_DOWN(pObj->pHead,ptmp);
    }
	if(ret==RET_ERR){// 添加到结尾
		ret=RET_OK;
		ptmp=pObj->pHead->pPrev;
		GDLNODE_INSERT_AFTER(ptmp,pAddNode);
		GDLINK_ADD_CNT();	
	}
    return ret;    
}

static int GDLink_CmpIDArray(tGDLHead* pObj,uint16_t ArraySz,uint8_t* pArray){ // For UT 测试 
	
	int ret = RET_ERR;
	int cnt = 0;
    int i;
	tDLNode* ptmp=NULL;
	
	if(pObj == NULL) 			{ LLOG_ERR(); return ret;}
	if(pArray == NULL)			{ LLOG_ERR(); return ret;}	
	if(ArraySz == 0)			{ LLOG_ERR(); return ret;}	

	if((pObj->pHead == NULL)){	// Frist Node
		LLOG_MARK();
		return RET_ERR;
	}
	
	ret = RET_OK;
	cnt = ArraySz;
	i = 0;
	ptmp=pObj->pHead;
    while(1){
		
		if(RET_EQ != pObj->pObjCmp((void*)pArray[i++],(void*)ptmp) ){ 
			// LLOG_MARK();
			
			LLOG("inpara %d\n",pArray[--i]);
			ret = RET_ERR;
			break;
		}
		cnt--;
		if(cnt == 0){
			break;
		}
		GDLINK_ITERATOR_DOWN(pObj->pHead,ptmp);
    }

    return ret;    
}

#endif

#ifdef CFG_GDLINK_MODE	/*** 单元测试 refer code */

typedef struct GDLink_Node_Demo{
	uint8_t Id;
	uint8_t Prio;
	tDLNode DNode;
	uint8_t* pName;
} tDNode;

tDNode* DNode_CreateByName(uint8_t ID,uint8_t* pName,uint8_t Prio){
	
	tDNode* pObj=NULL;
	pObj=(tDNode*)L_MALLOC(sizeof(tDNode));
	if(pObj == NULL){
		return pObj;
	}

	MEMSET((uint8_t*)pObj,0,sizeof(tDNode));
	pObj->Id		= ID;
	pObj->pName		= pName;
	pObj->Prio		= Prio;
	
	return pObj;
}

static int DemoNode_CmpRule(void* InPara,void* pNode){
	int ret = RET_ERR;
	tDNode* ptmp;
	ptmp = CC_LIST_ENTRY(((tDNode*)pNode),tDNode,DNode);
	if( ptmp->Id ==  ((uint8_t)InPara)){
		ret = RET_EQ;
	}
	else if(ptmp->Id > ((uint8_t)InPara)){
		ret = RET_GT;
	}
	else{
		ret = RET_LT;
	}
//	LLOG("ID %d\n",ptmp->Id);
	return ret;
}

static int DemoNode_Show(tDLNode* pNode){
	
	tDNode* ptmp;
	ptmp = CC_LIST_ENTRY(pNode,tDNode,DNode); // 获取对应对象
	// LLOG("[%d:%s]->",ptmp->Id,ptmp->pName);
	LLOG("[%d]->",ptmp->Id);
	return RET_OK;
}

//
static int DemoNode_CmpPrio(void* InPara,void* b){
	int ret=RET_ERR;
	tDNode* TmpB;
	tDNode* TmpA;
	
	
	TmpA=CC_LIST_ENTRY(InPara,tDNode,DNode);
	TmpB=CC_LIST_ENTRY(b,tDNode,DNode);
	
	// LLOG("Prio A[%d]-B[%d]\n",TmpA->Prio,TmpB->Prio);
	if( TmpA->Prio > TmpB->Prio){
		ret=RET_GT;
	}
	else if(TmpA->Prio == TmpB->Prio) {
		ret=RET_EQ;
	}
	else {
		ret=RET_LT;
	}
	// LLOG("ret[%d]\n",ret);
	return ret;
}

static int DemoNode_Prio_CBFunc(tDLNode* pNode){
	
	tDNode* ptmp;
	ptmp=CC_LIST_ENTRY(pNode,tDNode,DNode);
	LLOG("->[%d %s]",ptmp->Prio,ptmp->pName);
	return RET_OK;
}

tGDLHead* 	g_pGDLink_UT;
tDNode* 	g_FreeNodeBuf[10];
tDLNode* 	g_pDLNode[10];

#define ShowDLink(A) GDLink_ShowCBF(A,pObj,DemoNode_Show)

static uint8_t g_CmpRet_7[]={4,3,1,2,5};
static uint8_t g_CmpRet_del12[]={3,2};
static uint8_t g_CmpRet_16[]={3,2,4,1};

int UT_GDLink(void){
	
	int ret=RET_ERR;
	int i,j;
	tGDLHead* pObj;
	tGDLHead* pObjPrio;
	
	pObj		= GDLink_CreateByName("GDLink-UT",DemoNode_CmpRule);
	pObjPrio	= GDLink_CreateByName("GDLink-UT2",DemoNode_CmpPrio);
	g_pGDLink_UT= pObj;
	
	LLOG_MARK();
	
	LLOG("\n==== ==== ==== Create Notes\n");
	i=0;
	g_FreeNodeBuf[i++] = DNode_CreateByName(i+1,"NodeA",13);
	g_FreeNodeBuf[i++] = DNode_CreateByName(i+1,"NodeB",10);
	g_FreeNodeBuf[i++] = DNode_CreateByName(i+1,"NodeC",12);
	g_FreeNodeBuf[i++] = DNode_CreateByName(i+1,"NodeD",19);
	g_FreeNodeBuf[i++] = DNode_CreateByName(i+1,"NodeE",17);
	g_FreeNodeBuf[i++] = DNode_CreateByName(i+1,"NodeF",9);
	g_FreeNodeBuf[i++] = DNode_CreateByName(i+1,"NodeG",12);

	for(j=0;j<i;j++)
		g_pDLNode[j]=&g_FreeNodeBuf[j]->DNode;
	
	
	
	#if 1 // add nodes  // Step1: 添加节点
	LLOG("\n==== ==== ==== Add Notes\n");
	i=0;
	UT_CHECK(RET_ERR == GDLink_AddAfter(pObj,g_pDLNode[i],g_pDLNode[i+1]));	
	ShowDLink("Step1 :is empty"); // empty
	
	// 
	UT_CHECK(RET_OK	== GDLink_AddAfter(pObj,NULL,g_pDLNode[i++]) );
	// ShowDLink("Step2 : add frist node");
	
	UT_CHECK(RET_ERR == GDLink_AddAfter(pObj,NULL,g_pDLNode[i]) );//id2
	// ShowDLink("Step3 : refer node err");

	UT_CHECK(RET_OK	== GDLink_AddAfter(pObj,g_pDLNode[i-1],g_pDLNode[i]) );i++;
	// ShowDLink("Step4 : add node");
	
	UT_CHECK(RET_OK == GDLink_AddToHead(pObj,g_pDLNode[i++]) );//id3
	// ShowDLink("Step5");
	
	UT_CHECK(RET_OK == GDLink_AddToHead(pObj,g_pDLNode[i++]) );//id4
	// ShowDLink("Step6");
	
	UT_CHECK(RET_OK == GDLink_AddToTail(pObj,g_pDLNode[i++]) );
	// ShowDLink("Step7");
	UT_CHECK(RET_OK == GDLink_CmpIDArray(pObj,sizeof(g_CmpRet_7),&g_CmpRet_7[0]));

	LLOG("\n==== ==== ==== Del Notes\n");	
	UT_CHECK(g_pDLNode[0]==GDLink_DelByNodePtr(pObj,g_pDLNode[0]) );
	// ShowDLink("Step8: del mid node"); // 中间节点
	
	UT_CHECK(g_pDLNode[0]!=GDLink_DelByNodePtr(pObj,g_pDLNode[0]) );
	// ShowDLink("Step9 : del empty node");
	
	UT_CHECK(g_pDLNode[3]==GDLink_DelByNodePtr(pObj,g_pDLNode[3]) );
	// ShowDLink("Step10: del head node");
	
	UT_CHECK(g_pDLNode[4]==GDLink_DelByNodePtr(pObj,g_pDLNode[4]) );
	// ShowDLink("Step11 : del tail node");
	UT_CHECK(RET_OK == GDLink_CmpIDArray(pObj,sizeof(g_CmpRet_del12),&g_CmpRet_del12[0]));
	
	
	
	LLOG("\n==== ==== ==== Clean All Notes\n");
	UT_CHECK(RET_OK==GDLink_AddToHead(pObj,g_pDLNode[0]) );
	UT_CHECK(RET_OK==GDLink_AddToHead(pObj,g_pDLNode[3]) );
	// ShowDLink("Step12");	

	UT_CHECK(RET_OK==GDLink_CleanALL(pObj) );
	ShowDLink("Step13 : is empty");
	
	// 
	LLOG("\n==== ==== ==== AddBefore API\n");
	UT_CHECK(RET_OK==GDLink_AddToHead(pObj,g_pDLNode[0]) );
	UT_CHECK(RET_OK==GDLink_AddToHead(pObj,g_pDLNode[1]) );
	// ShowDLink("Step14");
	UT_CHECK(RET_OK==GDLink_AddBefore(pObj,g_pDLNode[1],g_pDLNode[2]) );
	// ShowDLink("Step15");
	UT_CHECK(RET_OK==GDLink_AddBefore(pObj,g_pDLNode[0],g_pDLNode[3]) );
	// ShowDLink("Step16:insert :before tail");
	UT_CHECK(RET_OK == GDLink_CmpIDArray(pObj,sizeof(g_CmpRet_16),&g_CmpRet_16[0]));
	
	#endif
	
	#if 1 //TODO Sort
	LLOG("GDLink SortAdd:\n");
	UT_CHECK(RET_OK==GDLink_CleanALL(pObj) );	
	ShowDLink("Step17");
	for(i=0;i<7;i++){
		UT_CHECK(RET_OK==GDLink_SortAdd(pObjPrio,g_pDLNode[i]) );
		// UT_CHECK(RET_OK==GDLink_AddToHead(pObjPrio,g_pDLNode[i]) );
		GDLink_ShowCBF("Prio:",pObjPrio,DemoNode_Prio_CBFunc);
	}
	// GDLink_ShowCBF("Prio:",pObjPrio,DemoNode_Prio_CBFunc);
	ShowDLink("Step18");
	#endif
	
}

#endif

